﻿using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Memory;
using SqlSugar;
using System.IO;
using VueAdminService.Attributes;
using VueAdminService.DTO;
using VueAdminService.Utils;
using VueAdminService.VO;


namespace VueAdminService.Controllers
{
	/// <summary>
	/// 用户相关接口
	/// </summary>
	[ApiController]
	[Route("api/[controller]")]
	public class UserController : BaseController
	{
		protected readonly IConfiguration _configuration;
		protected readonly IWebHostEnvironment _webHostEnvironment;
		public UserController(IConfiguration configuration, IWebHostEnvironment webHostEnvironment, IServiceProvider serviceProvider) : base(serviceProvider)
		{
			_configuration = configuration;
			_webHostEnvironment = webHostEnvironment;
		}
		/// <summary>
		/// 获取验证码图片
		/// </summary>
		/// <param name="uuid">前端uuid</param>
		/// <returns></returns>
		[HttpGet("verifycode")]
		public FileContentResult GetVerifyCode([FromQuery] string uuid)
		{
			var code = VerifyCodeUtil.GenerateVerifyCode(int.Parse(_configuration["AppConfig:VerifyCodeLenth"]));//生成验证码	
			SetCache<string>(uuid, code);//设置缓存	

			var bytes = VerifyCodeUtil.GenerateImage(code);
			return File(bytes, "image/jpeg");//返回图片
		}
		/// <summary>
		/// 登录
		/// </summary>
		/// <param name="userName">用户名</param>
		/// <param name="password">密码</param>
		/// <param name="verifyCode">验证码</param>
		/// <param name="uuid">前端uuid</param>
		/// <returns></returns>
		[HttpPost("login")]
		public ResponseResult<ResponseLoginVO> Login([FromForm] string userName, [FromForm] string password, [FromForm] string verifyCode, [FromForm] string uuid)
		{
			if (string.IsNullOrWhiteSpace(userName))
			{
				return FailedResult<ResponseLoginVO>("用户名不能为空", null);
			}
			if (string.IsNullOrWhiteSpace(password))
			{
				return FailedResult<ResponseLoginVO>("密码不能为空", null);
			}
			try
			{
				var code = GetCache<string>(uuid);//获取缓存
				if (string.IsNullOrWhiteSpace(verifyCode) || code == null || !code.Equals(verifyCode, StringComparison.CurrentCultureIgnoreCase))
				{
					return FailedResult<ResponseLoginVO>("验证码错误", null);
				}
				var result = _dbClient.Queryable<UserDTO>()
					.LeftJoin<UserRoleDTO>((u, r) => r.UserId == u.UserId)
					.Where(u => u.UserName == userName && u.Password == SecurityUtil.EncryptByMD5(password))
					.Select<ResponseUserVO>((u, r) => new ResponseUserVO()
					{
						RoleId = r.RoleId,
					}, true)
					.ToList();
				if (result.Count == 1)
				{
					var user = result[0];
					//需要调整为判断数据字典来确定用户状态					
					string? rejectStatus = _configuration["AppConfig:RejectLoginUserStatus"];
					if (string.IsNullOrWhiteSpace(rejectStatus) && rejectStatus.Split(",").Contains(user.Status))
					{
						return FailedResult<ResponseLoginVO>("该用户被限制登陆，请联系管理员", null);
					}
					else
					{
						string? issuer = _configuration.GetValue<string>("Jwt:Issuer");
						string? audience = _configuration.GetValue<string>("Jwt:Audience");
						string? key = _configuration.GetValue<string>("Jwt:Key");
						int expires = 60;
						string? tmp = _configuration.GetValue<string>("Jwt:Expires");
						if (!string.IsNullOrWhiteSpace(tmp))
						{
							expires = int.Parse(tmp);
						}
						var token = TokenUtil.GenerateJwtToken(user.UserId, issuer, audience, key, expires);

						return SuccessResult(new ResponseLoginVO()
						{
							Token = token,
							User = user
						});
					}
				}
				else
				{
					return FailedResult<ResponseLoginVO>("用户名或密码错误", null);
				}
			}
			catch (Exception ex)
			{
				LogError(ex, "登陆失败");
				return ErrorResult<ResponseLoginVO>("内部错误", null);
			}
		}
		/// <summary>
		/// 注销
		/// </summary>		
		/// <returns></returns>
		[HttpGet("logout")]
		[TokenRequired]
		public ResponseResult<bool> Logout()
		{
			try
			{
				//string? userId=TokenUtil.GetValueFromJwtToken(token,"userId");

				return SuccessResult(true);
			}
			catch (Exception ex)
			{
				LogError(ex, "注销失败");
				return ErrorResult("内部错误", false);
			}
		}

		/// <summary>
		/// 分页获取用户列表
		/// </summary>
		/// <param name="pageIndex">当前页</param>
		/// <param name="pageSize">每页记录数</param>
		/// <param name="keyword">关键字</param>
		/// <param name="status">用户状态</param>
		/// <returns></returns>
		[HttpGet("pagelist")]
		[TokenRequired]
		public ResponsePageResult<List<ResponseUserVO>> GetList([FromQuery] int pageIndex, [FromQuery] int pageSize, [FromQuery] string? keyword, [FromQuery] string? status, [FromQuery] string? roleId)
		{
			try
			{
				int rows = 0;
				var list = _dbClient.Queryable<UserDTO>()
					.LeftJoin<UserRoleDTO>((u, ur) => ur.UserId == u.UserId)
					.LeftJoin<RoleDTO>((u,ur,r)=>ur.RoleId==r.RoleId)
					.WhereIF(!string.IsNullOrWhiteSpace(keyword), u => u.UserName.Contains(keyword) || u.NickName.Contains(keyword) || u.Email.Contains(keyword) || u.Tel.Contains(keyword) || u.Bak.Contains(keyword))
					.WhereIF(!string.IsNullOrWhiteSpace(status), u => u.Status == status)
					.WhereIF(!string.IsNullOrWhiteSpace(roleId), (u, ur) => ur.RoleId == roleId)
					.Where(u => u.UserId != _configuration["AppConfig:SystemId"])//过滤掉内置用户
					.OrderByDescending(u => u.UserId)
					.Select<ResponseUserVO>((u, ur,r) => new ResponseUserVO()
					{
						RoleId = r.RoleId,
						RoleName=r.RoleName
					}, true)//属性一样的自动映射,只需手动映射不一样的
					.ToPageList(pageIndex, pageSize, ref rows);

				return SuccessPageResult(list, rows);
			}
			catch (Exception ex)
			{
				LogError(ex, "获取用户列表失败");
				return ErrorPageResult<List<ResponseUserVO>>("获取用户列表失败");
			}
		}
		/// <summary>
		/// 获取用户详情
		/// </summary>
		/// <param name="userId">用户id</param>		
		/// <returns></returns>
		[HttpGet("{userId}")]
		[TokenRequired]
		public ResponseResult<ResponseUserVO> Get(string userId)
		{
			try
			{
				var user = _dbClient.Queryable<UserDTO>()
					.Select<ResponseUserVO>()
					.First(u => u.UserId == userId);

				return SuccessResult(user);
			}
			catch (Exception ex)
			{
				LogError(ex, "获取用户失败");
				return ErrorResult<ResponseUserVO>("获取用户失败", null);
			}
		}
		/// <summary>
		/// 添加用户
		/// </summary>
		/// <param name="vo">用户实体</param>
		/// <returns></returns>
		[HttpPost]
		[TokenRequired]
		public ResponseResult<bool> Add([FromBody] RequestAddUserVO vo)
		{
			try
			{
				if (_dbClient.Queryable<UserDTO>().Where(u => u.UserName == vo.UserName).Count() > 0)
				{
					return FailedResult("用户名已存在,请更换后再试", false);
				}
				string userId = SnowFlakeSingle.Instance.NextId().ToString();// Guid.NewGuid().ToString("N");
				_dbClient.Ado.BeginTran();
				_dbClient.Insertable<UserDTO>(new UserDTO()
				{
					UserId = userId,
					UserName = vo.UserName,
					NickName = string.IsNullOrEmpty(vo.NickName) ? vo.UserName : vo.NickName,
					Password = SecurityUtil.EncryptByMD5(_configuration["AppConfig:DefaultPassword"]),
					Email = vo.Email,
					Tel = vo.Tel,
					Bak = vo.Bak
				}).ExecuteCommand();

				_dbClient.Insertable<UserRoleDTO>(new UserRoleDTO()
				{
					UserRoleId = SnowFlakeSingle.Instance.NextId().ToString(),//Guid.NewGuid().ToString("N"),
					UserId = userId,
					RoleId = vo.RoleId
				}).ExecuteCommand();
				_dbClient.Ado.CommitTran();
				return SuccessResult(true);
			}
			catch (Exception ex)
			{
				_dbClient.Ado.RollbackTran();
				LogError(ex, "添加用户失败");
				return ErrorResult("添加用户失败", false);
			}
		}
		/// <summary>
		/// 删除用户
		/// </summary>
		/// <param name="userId">用户Id</param>
		/// <returns></returns>
		[HttpDelete("{userId}")]
		[TokenRequired]
		public ResponseResult<bool> Delete(string userId)
		{
			if (userId == _configuration["AppConfig:SystemId"])
			{
				return FailedResult("内置用户不能删除", false);
			}
			try
			{
				_dbClient.Deleteable<UserDTO>(u => u.UserId == userId).ExecuteCommand();

				return SuccessResult(true);
			}
			catch (Exception ex)
			{
				LogError(ex, "删除用户失败");
				return ErrorResult("删除用户失败", false);
			}
		}
		/// <summary>
		/// 修改用户
		/// </summary>
		/// <param name="vo">用户实体</param>
		/// <returns></returns>
		[HttpPut]
		[TokenRequired]
		public ResponseResult<bool> Update([FromBody] RequestEditUserVO vo)
		{
			try
			{
				_dbClient.Ado.BeginTran();
				_dbClient.Updateable<UserDTO>(new UserDTO()
				{
					UserId = vo.UserId,
					NickName = vo.NickName,
					Email = vo.Email,
					Tel = vo.Tel,
					Bak = vo.Bak,
					Status = vo.Status
				}).IgnoreColumns(u => new { u.UserName, u.Password })//忽略账号、密码字段
				.ExecuteCommand();

				var role = _dbClient.Queryable<UserRoleDTO>().First(u => u.UserId == vo.UserId);
				if (role != null)
				{
					role.RoleId = vo.RoleId;
					_dbClient.Updateable<UserRoleDTO>(role).ExecuteCommand();//修改角色
					_dbClient.Ado.CommitTran();
				}

				return SuccessResult(true);
			}
			catch (Exception ex)
			{
				_dbClient.Ado.RollbackTran();
				LogError(ex, "修改用户失败");
				return ErrorResult("修改用户失败", false);
			}
		}
		/// <summary>
		/// 修改自己的用户信息
		/// </summary>
		/// <param name="vo">用户实体</param>
		/// <returns></returns>
		[HttpPut("info")]
		[TokenRequired]
		public ResponseResult<bool> UpdateInfo([FromBody] RequestEditUserInfoVO vo)
		{
			var token = Request.Headers["token"].ToString();
			string userId = TokenUtil.GetValueFromJwtToken(token, "userId").ToString();

			try
			{
				_dbClient.Updateable<UserDTO>(new UserDTO()
				{
					UserId = userId,
					NickName = vo.NickName,
					Email = vo.Email,
					Tel = vo.Tel
				}).UpdateColumns(u => new { u.NickName, u.Email, u.Tel })
				.ExecuteCommand();
				return SuccessResult(true);
			}
			catch (Exception ex)
			{
				LogError(ex, "修改用户信息失败");
				return ErrorResult("修改用户信息失败", false);
			}
		}
		/// <summary>
		/// 修改自己的头像
		/// </summary>
		/// <param name="vo"></param>
		/// <returns></returns>
		[HttpPut("avatar")]
		[TokenRequired]
		public ResponseResult<bool> UpdateAvatar([FromBody] RequestFileVO vo)
		{
			var token = Request.Headers["token"].ToString();
			string userId = TokenUtil.GetValueFromJwtToken(token, "userId").ToString();

			try
			{
				//获取路径				
				string extension = Path.GetExtension(vo.FileName).ToLower();
				string fileName = $"{userId}{extension}";
				var webRootPath = _webHostEnvironment.WebRootPath;
				string avatarPath = Path.Combine(webRootPath, "Avatar");

				string avatarFileName = Path.Combine(avatarPath, fileName);
				if (!Directory.Exists(avatarPath))
				{ //目录不存在则创建
					Directory.CreateDirectory(avatarPath);
				}
				//先删除之前的文件避免垃圾文件
				var user = _dbClient.Queryable<UserDTO>().First(u => u.UserId == userId);
				if (user != null && user.Avatar != "default.png")
				{
					string oldFileName = Path.Combine(avatarPath, user.Avatar);
					if (System.IO.File.Exists(oldFileName))
					{
						System.IO.File.Delete(Path.Combine(avatarPath, user.Avatar));
					}
				}
				//存储文件
				using (FileStream fs = new FileStream(avatarFileName, FileMode.OpenOrCreate))
				{
					//去掉以"data:image/png;base64,"开头的字符串
					string base64 = vo.Base64String;
					if (vo.Base64String.Contains(','))
					{
						base64 = vo.Base64String.Split(",")[1];
					}
					byte[] buffer = Convert.FromBase64String(base64);
					fs.Write(buffer, 0, buffer.Length);
					fs.Close();
				}

				//修改字段
				_dbClient.Updateable<UserDTO>(new UserDTO()
				{
					UserId = userId,
					Avatar = fileName,
				}).UpdateColumns(u => new { u.Avatar })//只更新头像
					.ExecuteCommand();
				return SuccessResult(true);
			}
			catch (Exception ex)
			{
				LogError(ex, "修改用户头像失败");
				return ErrorResult("修改用户头像失败", false);
			}
		}
		/// <summary>
		/// 重置用户密码
		/// </summary>
		/// <param name="userId"></param>
		/// <returns></returns>
		[HttpPut("resetpwd/{userId}")]
		[TokenRequired]
		public ResponseResult<bool> ResetPwd(string userId)
		{
			try
			{
				_dbClient.Updateable<UserDTO>(new UserDTO()
				{
					UserId = userId,
					Password = SecurityUtil.EncryptByMD5(_configuration["AppConfig:DefaultPassword"]),
				}).UpdateColumns(u => new { u.Password })//只更新密码列
				.ExecuteCommand();
				return SuccessResult(true);
			}
			catch (Exception ex)
			{
				LogError(ex, "重置密码失败");
				return ErrorResult("重置密码失败", false);
			}
		}
		/// <summary>
		/// 修改密码
		/// </summary>
		/// <param name="vo">请求实体</param>		
		/// <returns></returns>
		[HttpPut("change")]
		[TokenRequired]
		public ResponseResult<bool> ChangePassword([FromBody] RequestChangePwdVO vo)
		{
			if (string.IsNullOrWhiteSpace(vo.OldPassword) || string.IsNullOrWhiteSpace(vo.NewPassword))
			{
				return FailedResult("旧密码或新密码不能为空", false);
			}
			if (vo.NewPassword == vo.OldPassword)
			{
				return FailedResult("新密码不能与旧密码相同", false);
			}

			try
			{
				var token = Request.Headers["token"];
				string userId = TokenUtil.GetValueFromJwtToken(token, "userId").ToString();
				var user = _dbClient.Queryable<UserDTO>().First(o => o.UserId == userId);

				if (user == null)
				{
					return FailedResult("用户不存在", false);
				}
				if (user.Password != SecurityUtil.EncryptByMD5(vo.OldPassword))
				{
					return FailedResult("旧密码错误", false);
				}

				_dbClient.Updateable<UserDTO>(new UserDTO()
				{
					UserId = userId,
					Password = SecurityUtil.EncryptByMD5(vo.NewPassword),
				}).UpdateColumns(u => new { u.Password })//只更新密码列
				.ExecuteCommand();
				return SuccessResult(true);
			}
			catch (Exception ex)
			{
				LogError(ex, "修改密码失败");
				return ErrorResult("修改密码失败", false);
			}
		}
	}
}
